/* 
 * File:   Nivel.cpp
 * Author: fibrizo
 * 
 * Created on 24 de mayo de 2014, 19:13
 */

#include "Nivel.h"
#include <string>
#include <vector>
#include "MaterialFisico.h"
#include "Tierra.h"
#include "Caja.h"
#include "Metal.h"
#include "Bomba.h"
#include "Mapa.h"
#include "Bomberman.h"
#include "Planta.h"
#include "Enemigo.h"
#include "ZombieVerde.h"
#include "ZombieRojo.h"
#include "ZombieAzul.h"
#include "RandomGenerator.h"

using std::string;
using std::vector;

/***********************************************************************/
/*                              CONSTRUCTOR                            */
/***********************************************************************/

Nivel::Nivel() {
    this->mapa = Mapa();
    this->inicializado = false;
    this->terminado = false;
    this->cantZombiesAzules = 0;
    this->cantZombiesRojos = 0;
    this->cantZombiesVerdes = 0;
}

Nivel::Nivel(int tamanio) {
    this->terminado = false;
    Mapa mapaVacio = this->mapa;
    this->mapa = Mapa(tamanio);
    this->inicializado = false;
    this->cantZombiesAzules = 0;
    this->cantZombiesRojos = 0;
    this->cantZombiesVerdes = 0;
}

Nivel::Nivel(const Nivel& orig) {
}

/***********************************************************************/
/*                            METODOS PRIVADOS                         */
/***********************************************************************/

void Nivel::actualizar() {
    
    for (vector<Bomberman*>::iterator iter = personajes.begin(); iter != personajes.end(); iter++) {
        //if ((*iter)->respawnear())
            //mapa.
        mapa.moverElemento((*iter));
        bombas.push_back((*iter)->colocarBomba());
        if ((*iter)->estaVivo()) {
            personajes.erase(iter);
        }
    }
    
    for (vector<Enemigo*>::iterator iter = enemigos.begin(); iter != enemigos.end(); iter++) {
        mapa.moverElemento((*iter));
         if ((*iter)->estaVivo()) {
            Enemigo* aux = (*iter);
            enemigos.erase(iter);
            delete aux;
        }
    }
    
    for (unsigned int i = 0; i < plantas.size(); i++) {
        bombas.push_back((plantas[i])->disparar());
    } 
    
    list<Bomba*>::iterator it = bombas.begin();
    while (it != bombas.end()) {
        if ((*it)->yaExploto()) {
            Bomba* aux = (*it);
            bombas.erase(it);
            delete aux;
        }
        (*it)->actuar(mapa);
        it++;
    }                              
    
    
    for (unsigned int i = 0; i < personajes.size(); i++) {
       this->mapa.resolverColisiones(personajes[i]);
    }

}


bool Nivel::termino() {
    return terminado;
}

/***********************************************************************/
/*                            METODOS PUBLICOS                         */
/***********************************************************************/

void Nivel::setZombies(size_t verdes, size_t azules, size_t rojos) {
    this->cantZombiesVerdes = verdes;
    this->cantZombiesAzules = azules;
    this->cantZombiesRojos = rojos;
    
    for(size_t i = 0; i < verdes; i++) {
        ZombieVerde* nuevoVerde = new ZombieVerde();
        (this->enemigos).push_back(nuevoVerde);
    }
    for(size_t i = 0; i < azules; i++) {
        ZombieAzul* nuevoAzul = new ZombieAzul();
        (this->enemigos).push_back(nuevoAzul);
    }
    for(size_t i = 0; i < rojos; i++) {
        ZombieRojo* nuevoRojo = new ZombieRojo();
        (this->enemigos).push_back(nuevoRojo);
    }
}

void Nivel::inicializar(string tileMap, vector<Bomberman*> listaDeBombermans) {
    mapa.inicializar();
    const char* cadenaMapa = tileMap.c_str();
    int i = 0;
    int j = 0;
    int x = 0;
    int indiceBombermans = 0;
    int tam = mapa.getTamanio();
    //MaterialFisico* material = NULL;
    Coordenada coord = Coordenada(0,0);
    while (x < tam) {
        j = 0;
        while (j < tam) {
            
            if (cadenaMapa[i] == CAJA) {mapa.establecerMaterial(new Caja(), coord);}
            else if (cadenaMapa[i] == CAJA_CON_ZOMBIE){
                mapa.establecerMaterial(new Caja(), coord);
                ZombieVerde* zombie = new ZombieVerde();
                enemigos.push_back(zombie);
                mapa.ubicarElemento(zombie, coord);
            }
            else if (cadenaMapa[i] == METAL) {mapa.establecerMaterial(new Metal(), coord);}
            else {
                if (cadenaMapa[i] == ZOMBIE_VERDE) {
                    ZombieVerde* zombie = new ZombieVerde();
                    enemigos.push_back(zombie);
                    mapa.ubicarElemento(zombie, coord);
                }
                else if (cadenaMapa[i] == ZOMBIE_ROJO) {
                    ZombieRojo* zombie = new ZombieRojo();
                    enemigos.push_back(zombie);
                    mapa.ubicarElemento(zombie, coord);
                }
                else if (cadenaMapa[i] == ZOMBIE_AZUL) {
                    ZombieAzul* zombie = new ZombieAzul();
                    enemigos.push_back(zombie);
                    mapa.ubicarElemento(zombie, coord);
                }
                else if (cadenaMapa[i] == PLANTA) {
                    Planta* planta = new Planta(establecerDireccionPlanta(coord), coord);
                    plantas.push_back(planta);
                    mapa.ubicarElemento(planta, coord);
                }
                else if ((cadenaMapa[i] >= COMIENZO_BOMBERMANS) && (cadenaMapa[i] <= FIN_BOMBERMANS)) {
                    listaSpawnBomberman.push_back(coord);
                    mapa.ubicarElemento(listaDeBombermans[indiceBombermans], coord);
                    indiceBombermans++;
                }
            }
            coord.incrementarX();
            j++;
            i++;
        }
        coord = Coordenada(0, coord.getY());
        coord.incrementarY();
        x++;
    }
    //delete coord;
    inicializado = true;
}


// Metodo privado de Nivel. En base a una coordenada de una planta
// devuelve a que direccion deberia apuntar.
string Nivel::establecerDireccionPlanta(Coordenada coord) {
    int x = coord.getX();
    int y = coord.getY();
    RandomGenerator generador;
    vector<string> dir = {"arriba", "abajo", "derecha", "izquierda"};
    vector<string> primerCuadrante = {"abajo", "derecha"};
    vector<string> segundoCuadrante = {"abajo", "izquierda"};
    vector<string> tercerCuadrante = {"arriba", "derecha"};
    vector<string> cuartoCuadrante = {"arriba", "izquierda"};
    if ((x < 0) && (y > 0)) return primerCuadrante[generador.generate(0,1)];
    else if ((x > 0) && (y > 0)) return segundoCuadrante[generador.generate(0,1)];
    else if ((x < 0) && (y < 0)) return tercerCuadrante[generador.generate(0,1)];
    else if ((x < 0) && (y < 0)) return cuartoCuadrante[generador.generate(0,1)];
    else return dir[generador.generate(0,3)]; 
}



/***********************************************************************/
/*                              DESTRUCTOR                             */
/***********************************************************************/


Nivel::~Nivel() {
    while(!enemigos.empty()) {
        Enemigo* aux = enemigos.back();
        enemigos.pop_back();
        delete aux;
    }
    while(!plantas.empty()) {
        Planta* aux = plantas.back();
        plantas.pop_back();
        delete aux;
    }
    while(!bombas.empty()) {
        Bomba* aux = bombas.back();
        bombas.pop_back();
        delete aux;
    }
}

